/**
 * @file app\data_proc\dp_key.c
 *
 * Copyright (C) 2023
 *
 * dp_key.c is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author zhuodada
 *
 * @encoding utf-8
 */

/*---------- includes ----------*/
#include "key.h"
#include "cpu.h"
#include "device.h"
#include "gpio_group.h"
#include "multi_button.h"
#include "options.h"
#include "protocol_mobus.h"
#include "resources.h"
#include "soft_timer.h"
#include "storage.h"

/*---------- macro ----------*/
#define TAG "DPKey"

/*---------- type define ----------*/
/*---------- variable prototype ----------*/
/*---------- function prototype ----------*/
/*---------- variable ----------*/
static void* proc = NULL;
static void* proc_timer = NULL;
static void* dev_key = NULL;
static struct Button button[8] = { 0 };
static struct storage_led_struct* led_lisicar = NULL;
gpio_group_describe_t* pdesc = NULL;
static struct storage_mobus_device* dev = NULL;
/*---------- function ----------*/
static uint8_t read_button1_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX1 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t read_button2_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX2 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t read_button3_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX3 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t read_button4_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX4 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t read_button5_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX5 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t read_button6_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX6 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t read_button7_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX7 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t read_button8_gpio() {
    uint8_t var1 = 0;
    device_ioctl(dev_key, (GROUP_INDEX8 | IOCTL_GROUP_GET), &var1);
    return var1;
}
static uint8_t tempbuff[3] = { 0 };
static uint8_t reset_time = 0, last_keynum = 0xff, reset_flag = 0;
void button_callback(void* button) {
    static uint16_t capture_math_time = 0x00, reset_math_time = 0;
    volatile uint32_t btn_event_val = 0, abs = 0;
    static volatile uint32_t sys_tic = 0, sys_tic_old = 0, key1_sys_tic = 0, key1_sys_tic_old = 0;
    static volatile uint8_t btn_key_val_old = 0xff, btn_key_val = 0, Tcmd = 0;
    btn_event_val = get_button_event((struct Button*)button);
    btn_key_val = get_button_keyid((struct Button*)button);
    switch (btn_event_val) {
    case PRESS_DOWN:
//        xlog_tag_info(TAG, "key %d , __get_ticks %d \n", btn_key_val, (uint32_t)__get_ticks());
//        sys_tic = __get_ticks();
//        abs = sys_tic > sys_tic_old ? sys_tic - sys_tic_old : sys_tic_old - sys_tic;
//        if (abs < 100) {
//            xlog_tag_info(TAG, "sys_tic_old %d, sys_tic is %d, abs is %d\n,", sys_tic_old, sys_tic, abs);
//            return;
//        }
//        sys_tic_old = sys_tic;
        if (btn_key_val == 0)
        {
            if (reset_time == 0)
            {
                reset_time = 40;
            }
            else
            {
                reset_flag = 1;
            }
            last_keynum = btn_key_val;
        }
        else
        {
            last_keynum = 0xff; reset_flag = 0; reset_time = 0;
        }
        if (no_storage.LisicarD_Temp.autoplay_mode == 1 && no_storage.LisicarD_Temp.net_mode == 0)
        {
            if (btn_key_val == 0)
            {
                no_storage.LisicarD_Temp.s1_led_sat = !no_storage.LisicarD_Temp.s1_led_sat;
                xlog_tag_info(TAG, "in local s1_led_sat is %d\n", no_storage.LisicarD_Temp.s1_led_sat);
            }
            else if (btn_key_val == 1)
            {
                no_storage.LisicarD_Temp.s2_led_sat = !no_storage.LisicarD_Temp.s2_led_sat;
                xlog_tag_info(TAG, "in local s2_led_sat is %d\n", no_storage.LisicarD_Temp.s2_led_sat);
            }
            else if (btn_key_val == 2)
            {
                no_storage.LisicarD_Temp.s3_led_sat = !no_storage.LisicarD_Temp.s3_led_sat;
                xlog_tag_info(TAG, "in local s3_led_sat is %d\n", no_storage.LisicarD_Temp.s3_led_sat);
            }
            else if (btn_key_val == 3)
            {
                no_storage.LisicarD_Temp.s4_led_sat = !no_storage.LisicarD_Temp.s4_led_sat;
                xlog_tag_info(TAG, "in local s4_led_sat is %d\n", no_storage.LisicarD_Temp.s4_led_sat);
            }
            else if (btn_key_val == 4)
            {
                no_storage.LisicarD_Temp.s5_led_sat = !no_storage.LisicarD_Temp.s5_led_sat;
                xlog_tag_info(TAG, "in local s5_led_sat is %d\n", no_storage.LisicarD_Temp.s5_led_sat);
            }
            else if (btn_key_val == 5)
            {
                no_storage.LisicarD_Temp.s6_led_sat = !no_storage.LisicarD_Temp.s6_led_sat;
                xlog_tag_info(TAG, "in local s6_led_sat is %d\n", no_storage.LisicarD_Temp.s6_led_sat);
            }
            else if (btn_key_val == 6)
            {
                no_storage.LisicarD_Temp.s7_led_sat = !no_storage.LisicarD_Temp.s7_led_sat;
                xlog_tag_info(TAG, "in local s7_led_sat is %d\n", no_storage.LisicarD_Temp.s7_led_sat);
            }
            else if (btn_key_val == 7)
            {
                no_storage.LisicarD_Temp.s8_led_sat = !no_storage.LisicarD_Temp.s8_led_sat;
                xlog_tag_info(TAG, "in local s8_led_sat is %d\n", no_storage.LisicarD_Temp.s8_led_sat);
            }
            led_lisicar->LisicarD_struct.background =
                (uint16_t)((no_storage.LisicarD_Temp.s12_led_sat << 15) | \
                    (no_storage.LisicarD_Temp.s11_led_sat << 14) | \
                    (no_storage.LisicarD_Temp.s10_led_sat << 13) | \
                    (no_storage.LisicarD_Temp.s9_led_sat << 12) | \
                    (no_storage.LisicarD_Temp.null_3 << 11) | \
                    (no_storage.LisicarD_Temp.null_2 << 10) | \
                    (no_storage.LisicarD_Temp.null_1 << 9) | \
                    (no_storage.LisicarD_Temp.backgroud_led << 8) | \
                    (no_storage.LisicarD_Temp.s8_led_sat << 7) | \
                    (no_storage.LisicarD_Temp.s7_led_sat << 6) | \
                    (no_storage.LisicarD_Temp.s6_led_sat << 5) | \
                    (no_storage.LisicarD_Temp.s5_led_sat << 4) | \
                    (no_storage.LisicarD_Temp.s4_led_sat << 3) | \
                    (no_storage.LisicarD_Temp.s3_led_sat << 2) | \
                    (no_storage.LisicarD_Temp.s2_led_sat << 1) | \
                    no_storage.LisicarD_Temp.s1_led_sat);
            xlog_tag_info(TAG, "LisicarD_struct.background is 0x%x\n", led_lisicar->LisicarD_struct.background);
        }
        else
        {
            Tcmd = P_DOWN;
            tempbuff[0] = btn_key_val + 1;
            tempbuff[1] = Tcmd;
            protocol_mobus_dev_report(MOBUS_FRAME_TYPE_COMMAND, 0, tempbuff, 2);
        }
        break;

    case PRESS_UP:
        sys_tic = 0;
        capture_math_time = 0x00;
        if (Tcmd == P_DOWN) {
            Tcmd = P_UP;
            tempbuff[0] = btn_key_val + 1;
            tempbuff[1] = Tcmd;
            protocol_mobus_dev_report(MOBUS_FRAME_TYPE_COMMAND, 0, tempbuff, 2);
        }
        break;
    case SINGLE_CLICK:
        sys_tic = __get_ticks();
        abs = sys_tic > sys_tic_old ? sys_tic - sys_tic_old : sys_tic_old - sys_tic;
        if (abs < 100) {
            xlog_tag_info(TAG, "sys_tic_old %d, sys_tic is %d, abs is %d\n,",
                sys_tic_old, sys_tic, abs);
            return;
        }
        sys_tic_old = sys_tic;
        break;
    case LONG_PRESS_HOLD:
        if (reset_flag == 1)
        {
            reset_math_time++;
            if (reset_math_time > 1000)
                reset_math_time = 1000;
            else if (reset_math_time > 200)
            {
                cpu_reset();
            }
        }
        break;
    }
}
static void multi_button_init(void) {
    bool err_flag = true;
    pdesc = ((device_t*)dev_key)->pdesc;
    assert(pdesc);
    no_storage.temp_key.key_num = pdesc->group_num_max;
    dev = (struct storage_mobus_device*)storage_get(STORAGE_AREA_DEVICE);
    assert(dev);
    dev->device.device_type = MOBUS_DEVICE_TYPE_LSKED;
    led_lisicar = (struct storage_led_struct*)storage_get(STORAGE_AREA_LIGHT_MODE);
    assert(led_lisicar);
    button_init(&button[0], read_button1_gpio, 0, 0);
    button_init(&button[1], read_button2_gpio, 0, 1);
    button_init(&button[2], read_button3_gpio, 0, 2);
    button_init(&button[3], read_button4_gpio, 0, 3);
    button_init(&button[4], read_button5_gpio, 0, 4);
    button_init(&button[5], read_button6_gpio, 0, 5);
    button_init(&button[6], read_button7_gpio, 0, 6);
    button_init(&button[7], read_button8_gpio, 0, 7);

    storage_set(STORAGE_AREA_DEVICE, dev, sizeof(struct storage_mobus_device));
    for (unsigned char i = 0; i < pdesc->group_num_max; i++) {
        button_attach(&button[i], PRESS_DOWN, button_callback);
        button_attach(&button[i], PRESS_UP, button_callback);
        button_attach(&button[i], SINGLE_CLICK, button_callback);
        button_attach(&button[i], LONG_PRESS_HOLD, button_callback);
        button_start(&button[i]);
    }
}

static void _timer_expired(timer_handle_t timer) {
    if (no_storage.led_temp_variable.dev_work_mode == LED_MODE_START)
        return;
    button_ticks();
    if (reset_time > 0)
        reset_time--;
    else
        last_keynum = 0xff;
}

bool app_key_poll(void) {
    bool _init_flag = false;
    dev_key = resources_get("dev_key");
    assert(dev_key);
    multi_button_init();
    /* create a timer for proc polling */
    proc_timer = soft_timer_create("KeyProcTimer", SFTIM_MODE_REPEAT,
        __ms2ticks(10), NULL, _timer_expired);
    assert(proc_timer);
    soft_timer_start(proc_timer);
    /*say hi */
    xlog_tag_message(TAG, "Initialize successfully\n");
    _init_flag = true;
    return _init_flag;
}
